const slog = require("single-line-log").stdout;

let replace = (str, token, value) => {
	return str.replace(new RegExp(`:${token}`, "g"), value);
};

module.exports = class ProgressBar {
	constructor(description = "Loading...", options) {
		this.description = description; // 描述文字

		if (typeof options == "number") {
			this.length = options || 50; // 进度条的长度(单位：字符)，默认设为 50
			this.incomplete = "░"; // 没完成的进度占位符
			this.complete = "█"; // 已完成的进度占位符
		} else if (options instanceof Object && Object.prototype.toString.call(options) === "[object Object]") {
			this.length = options.width || 50;
			this.incomplete = options.incomplete || "░"; // 没完成的进度占位符
			this.complete = options.complete || "█"; // 已完成的进度占位符
		} else {
			this.length = 50;
			this.incomplete = "░"; // 没完成的进度占位符
			this.complete = "█"; // 已完成的进度占位符
		}
	}

	render(arg = {}) {
		try {
			let { current = 0, total = 10 } = arg;
			if (total <= 0 || isNaN(total) || isNaN(current)) {
				return false;
			}

			let currNum = Math.floor((current / total) * this.length); // 计算需要多少个 █ 符号来拼凑图案

			let bar = [...new Array(this.length)]
				.map((m, i) => {
					if (i <= currNum - 1) {
						return this.complete;
					}
					return this.incomplete;
				})
				.join("");

			let percent = `${((current / total) * 100).toFixed(2)}%`;
			let exclude = ["bar", "percent"]; //不接收这些特殊的token

			let text = this.description;

			let keyArr = [];
			for (const key in arg) {
				if (Object.hasOwnProperty.call(arg, key) && !exclude.includes(key)) {
					keyArr.push([key, arg[key]]);
				}
			}
			// 排一下序，优先匹配key比较长的，例如 :total和:totalFormat,优先匹配:totalFormat，不然会出现100Format的情况，匹配了total，Format就保留了，主要防止出现多个token，前面或后面一截相同的情况，优先匹配长的token
			keyArr
				.sort((a, b) => {
					return b[0].length - a[0].length;
				})
				.forEach(([key, val]) => {
					text = replace(text, key, val);
				});

			text = replace(text, "percent", percent);
			text = replace(text, "current", current);
			text = replace(text, "total", total);
			text = replace(text, "bar", bar);

			// 在单行输出文本
			slog(text);
		} catch {}
	}
};
